package com.wiscamp.ninechapters.problems.infrastructure.gateway;

import com.wiscamp.ninechapters.common.GlobalState;
import com.wiscamp.ninechapters.problems.application.assemblers.ProblemAssembler;
import com.wiscamp.ninechapters.problems.domain.gateway.TagGateway;
import com.wiscamp.ninechapters.problems.domain.models.problems.problems.ProblemKnowledgePoint;
import com.wiscamp.ninechapters.tags.application.dto.command.BindTagCommand;
import com.wiscamp.ninechapters.tags.application.dto.command.UnbindTagCommand;
import com.wiscamp.ninechapters.tags.application.dto.vo.CourseOutlineVO;
import com.wiscamp.ninechapters.tags.application.dto.vo.CourseVO;
import com.wiscamp.ninechapters.tags.application.services.CourseAppService;
import com.wiscamp.ninechapters.tags.application.services.EntityAppService;
import com.wiscamp.ninechapters.tags.application.services.KnowledgePointAppService;
import com.wiscamp.ninechapters.tags.application.services.TagAppService;
import com.wiscamp.ninechapters.tags.domain.models.TagName;
import cube.common.core.CollectionUtils;
import jakarta.validation.constraints.NotEmpty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.Objects;

@Component
public class TagGatewayImpl implements TagGateway {

    private final CourseAppService courseAppService;

    private final TagAppService tagAppService;

    private final KnowledgePointAppService knowledgePointAppService;

    private final EntityAppService entityAppService;

    @Autowired
    public TagGatewayImpl(CourseAppService courseAppService, TagAppService tagAppService, KnowledgePointAppService knowledgePointAppService, EntityAppService entityAppService) {
        this.courseAppService = courseAppService;
        this.tagAppService = tagAppService;
        this.knowledgePointAppService = knowledgePointAppService;
        this.entityAppService = entityAppService;
    }

    public long getEntityIdByCode(String entityCode) {
        var entity = entityAppService.getEntityByCode(entityCode, GlobalState.APPLICATION_ID);
        if (Objects.nonNull(entity))
            return entity.getEntityId();
        return 0;
    }

    public Collection<Long> getChildKnowledgePointIds(@NotEmpty Collection<Long> pointIds) {
        return knowledgePointAppService.getChildKnowledgePointIds(pointIds);
    }

    @Override
    public boolean batchTag(String tagGroupName, String tagName, Collection<Long> problemIds) {
        var command = new BindTagCommand();
        command.setApplicationId(GlobalState.APPLICATION_ID);
        command.setGroupName(tagGroupName);
        command.setTagName(tagName);
        command.setEntityCode(GlobalState.ENTITY_PROBLEM);
        command.setPrimaryKeyIds(problemIds);
        return entityAppService.bindTag(command);
    }

    @Override
    public boolean batchUntag(String tagGroupName, String tagName, Collection<Long> problemIds) {
        var command = new UnbindTagCommand();
        command.setApplicationId(GlobalState.APPLICATION_ID);
        command.setGroupName(tagGroupName);
        command.setTagName(tagName);
        command.setEntityCode(GlobalState.ENTITY_PROBLEM);
        command.setPrimaryKeyIds(problemIds);
        return entityAppService.unbindTag(command);
    }

    public Collection<TagName> getTagNamesByProblem(long problemId) {
        var points = entityAppService.getTagNamesByPrimaryKey(GlobalState.APPLICATION_ID, GlobalState.ENTITY_PROBLEM, problemId);
        return CollectionUtils.toArrayList(points, ProblemAssembler.Instance::toTagName);
    }

    public Collection<Long> getProblemIdsByTags(Collection<Long> tagIds) {
        return entityAppService.getPrimaryKeyIdsByTags(GlobalState.APPLICATION_ID, GlobalState.ENTITY_PROBLEM, tagIds);
    }

    public TagName getTagByName(String groupName, String tagName) {
        var tagVO = tagAppService.getTagByName(groupName, tagName, GlobalState.APPLICATION_ID);
        return ProblemAssembler.Instance.toTagName(tagVO);
    }

    public Collection<ProblemKnowledgePoint> getKnowledgePointsByProblem(long problemId) {
        var points = entityAppService.getKnowledgePointsByPrimaryKey(GlobalState.APPLICATION_ID, GlobalState.ENTITY_PROBLEM, problemId);
        return CollectionUtils.toArrayList(points, ProblemAssembler.Instance::toNonPrimaryProblemKnowledgePoint);
    }

    public Collection<Long> getProblemIdsByKnowledgePoints(Collection<Long> pointIds) {
        return entityAppService.getPrimaryKeyIdsByKnowledgePoints(GlobalState.APPLICATION_ID, GlobalState.ENTITY_PROBLEM, pointIds);
    }

    public Collection<ProblemKnowledgePoint> getKnowledgePointsByProblems(Collection<Long> problemIds) {
        var points = entityAppService.getKnowledgePointsByPrimaryKeyIds(GlobalState.APPLICATION_ID, GlobalState.ENTITY_PROBLEM, problemIds);
        return CollectionUtils.toArrayList(points, ProblemAssembler.Instance::toNonPrimaryProblemKnowledgePoint);
    }

    public Collection<ProblemKnowledgePoint> getPrimaryKnowledgePointsByProblem(long entityKeyId, boolean isPrimary) {
        var points = entityAppService.getKnowledgePointsByPrimaryKey(GlobalState.APPLICATION_ID, GlobalState.ENTITY_PROBLEM, entityKeyId, isPrimary);
        for (var point : points) {
            point.setPrimary(isPrimary);
        }
        return CollectionUtils.toArrayList(points, ProblemAssembler.Instance::toNonPrimaryProblemKnowledgePoint);
    }


    public CourseVO getCourse(long courseId) {
        return courseAppService.getCourse(courseId);
    }

    public CourseOutlineVO getCourseOutline(long courseId, long outlineId) {
        var course = courseAppService.getCourse(courseId);
        var optionalOutline = course.getOutlines().stream().filter(o -> o.getOutlineId() == outlineId).findFirst();
        return optionalOutline.orElse(null);
    }
}
